package com.gitee.cui.netty.bytebuf;

import com.gitee.cui.util.Logger;
import io.netty.buffer.*;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.embedded.EmbeddedChannel;
import org.junit.Test;

/**
 * 缓冲区分配器测试类
 */
public class AllocatorTest {
    @Test
    public void showAlloc() {
        ByteBuf buffer = null;
        //方法一：默认分配器，分配初始容量为9，最大容量100的缓冲
        buffer = ByteBufAllocator.DEFAULT.buffer(9, 100);
        //方法二：默认分配器，分配初始为256，最大容量Integer.MAX_VALUE 的缓冲
        buffer = ByteBufAllocator.DEFAULT.buffer();
        //方法三：非池化分配器，分配基于Java的堆内存缓冲区
        buffer = UnpooledByteBufAllocator.DEFAULT.heapBuffer();
        //方法四：池化分配器，分配基于操作系统的管理的直接内存缓冲区
        buffer = PooledByteBufAllocator.DEFAULT.directBuffer();
        //…..其他方法

    }

    /**
     * 辅助方法，输出ByteBuf是否为直接内存，以及内存分配器
     * @param action
     * @param b
     */
    public static void printByteBuf(String action, ByteBuf b) {
        Logger.info("==================" + action + "==================");
        // true表示缓冲区为Java堆内存（组合缓冲区例外）
        // false表示缓冲区为操作系统管理的内存（组合缓冲区例外）
        Logger.info("b.hasArray: " + b.hasArray());
        // 输出内存分配器
        Logger.info("b.ByteBufAllocator: " + b.alloc());
    }

    static class AllocatorHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            printByteBuf("入站的ByteBuf", (ByteBuf) msg);
            ByteBuf buffer = ctx.alloc().buffer();
            buffer.writeInt(100);
            // 向模拟通道写入一个出站包，模拟数据出站，需要刷新通道才能获取到输出
            ctx.channel().writeAndFlush(buffer);
        }
    }

    /**
     * [main|AllocatorTest.printByteBuf] |>  ==================入站的ByteBuf==================
     * [main|AllocatorTest.printByteBuf] |>  b.hasArray: true
     * [main|AllocatorTest.printByteBuf] |>  b.ByteBufAllocator: UnpooledByteBufAllocator(directByDefault: true)
     *
     * [main|AllocatorTest.printByteBuf] |>  ==================出站的ByteBuf==================
     * [main|AllocatorTest.printByteBuf] |>  b.hasArray: false
     * [main|AllocatorTest.printByteBuf] |>  b.ByteBufAllocator: PooledByteBufAllocator(directByDefault: true)
     */
    @Test
    public void byteBufAllocatorTest() {
        ChannelInitializer<EmbeddedChannel> channelInitializer = new ChannelInitializer<EmbeddedChannel>() {

            @Override
            protected void initChannel(EmbeddedChannel ch) throws Exception {
                ch.pipeline().addLast(new AllocatorHandler());
            }
        };
        EmbeddedChannel embeddedChannel = new EmbeddedChannel(channelInitializer);
        // 配置通道的缓冲区分配器，这里是一个池化的分配器
        embeddedChannel.config().setAllocator(PooledByteBufAllocator.DEFAULT);
        ByteBuf buffer = Unpooled.buffer();
        buffer.writeInt(1);
        // 向模拟通道写入一个入站包，模拟数据入站
        embeddedChannel.writeInbound(buffer);
        // 获取通道的出站包
        ByteBuf outBuf = embeddedChannel.readOutbound();
        printByteBuf("出站的ByteBuf", outBuf);
    }
}